#rem
	TimelineFX Module by Peter Rigby
	
	Copyright (c) 2012 Peter J Rigby
	
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

#END

Import timelinefx

#REM
	summary: The effect class which is the main parent class for emitters
	Effect types are the main containers for emitters and has a set of global attributes that can effect any emitters it stores.
	The basic entity structure of an effect is: Effect -> Emitter(s) -> Particle(s)
#END
Class tlEffect Extends tlFXObject
	
	Private
	
	'Effect Settings:
	Field _class:Int
	Field emitatpoints:Int
	Field maxgx:Int
	Field maxgy:Int
	Field emission_type:Int
	Field ellipsearc:Float
	Field ellipseoffset:Int
	Field effectlength:Int
	Field uniform:Int
	Field traverseedge:Int
	Field endbehaviour:Int
	Field distancesetbylife:Int
	Field emissiontype:Int
	Field reversespawndirection:Int
	
	'Animation Properties
	Field animwidth:Int
	Field animheight:Int
	Field animx:Int
	Field animy:Int
	Field seed:Int
	Field looped:Int
	Field frameoffset:Int
	Field animzoom:Float
	
	'Overide flags
	Field overrideareasize:Int
	Field overrideemissionangle:Int
	Field overrideemissionrange:Int
	Field overrideangle:Int
	Field overridelife:Int
	Field overrideamount:Int
	Field overridevelocity:Int
	Field overridespin:Int
	Field overridesizex:Int
	Field overridesizey:Int
	Field overrideweight:Int
	Field overridealpha:Int
	Field overridestretch:Int
	Field overrideglobalzoom:Int
	
	'Other temp settings
	Field spawndirection:Int
	
	'Hierarchy
	Field parentemitter:tlEmitter
	
	'Map
	Field directory:StringMap<tlGameObject>
	
	'Particle Management
	Field pm:tlParticleManager
	Field particlecount:Int
	Field donottimeout:Int
	
	'Idle counter
	Field idletime:Int
	
	Field data:Object
	
	Field effectlayer:Int
	
	Public
	
	'Temp attribute values
	'There's no current angle becuase that sets the game object's local_rotation field
	Field currentsizex:Float
	Field currentsizey:Float
	Field currentvelocity:Float
	Field currentspin:Float
	Field currentweight:Float
	Field currentareawidth:Float
	Field currentareaheight:Float
	Field currentalpha:Float
	Field currentemissionangle:Float
	Field currentemissionrange:Float
	Field currentstretch:Float
	Field currentglobalzoom:Float
	
	Method New()
		Super.New()
		Local core:tlEffectCoreComponent = New tlEffectCoreComponent("Core")
		core.Effect = Self
		ImageBox = CreateBox(0, 0, 1, 1)
		AddComponent(core)
		DoNotRender = True
	End Method
	
	'properties	
	Method EffectLayer:Int() Property
		Return effectlayer
	End
	Method EffectLayer:Void(v:Int) Property
		effectlayer = v
	End	
	Method ParticleCount:Int() Property
		Return particlecount
	End
	Method ParticleCount:Void(v:Int) Property
		particlecount=v
	End
	Method DoNotTimeOut:Int() Property
		Return donottimeout
	End
	Method DoNotTimeOut:Void(v:Int)
		donottimeout = v
	End
	Method IdleTime:Int() Property
		Return idletime
	End
	Method IdleTime:Void(v:Int) Property
		idletime = v
	End
	Method Directory:StringMap<tlGameObject>() Property
		Return directory
	End
	Method Directory:Void(v:StringMap<tlGameObject>) Property
		directory = v
	End
	Method AddEffectToDirectory:Void(e:tlEffect)
		directory.Insert(e.Path.ToUpper, e)
		For Local em:tlGameObject = EachIn e.GetChildren
			AddEmitterToDirectory(tlEmitter(em))
		Next
	End
	Method AddEmitterToDirectory:Void(e:tlEmitter)
		directory.Insert(e.Path, e)
		For Local ef:tlGameObject = EachIn e.Effects
			AddEffectToDirectory(tlEffect(ef))
		Next
	End
	Method AddEffect:Void(e:tlEffect)
		directory.Insert(e.Path.ToUpper, e)
		For Local em:tlGameObject = EachIn e.GetChildren
			AddEmitter(tlEmitter(em))
		Next
	End
	Method AddEmitter:Void(e:tlEmitter)
		directory.Insert(e.Path.ToUpper, e)
		For Local ef:tlGameObject = EachIn e.Effects
			AddEffect(tlEffect(ef))
		Next
	End
	Method ParentEmitter:tlEmitter() Property
		Return parentemitter
	End
	Method ParentEmitter:Void(e:tlEmitter) Property
		parentemitter = e
	End
	Method EffectClass:Int() Property
		Return _class
	End
	Method EffectClass:Void(value:Int) Property
		_class = value
	End
	Method EmitatPoints:Int() Property
		Return emitatpoints
	End
	Method EmitatPoints:Void(value:Int) Property
		emitatpoints = value
	End
	Method MaxGX:Int() Property
		Return maxgx
	End
	Method MaxGX:Void(value:Int) Property
		maxgx = value
	End
	Method MaxGY:Int() Property
		Return maxgy
	End
	Method MaxGY:Void(value:Int) Property
		maxgy = value
	End
	Method EmissionType:Int() Property
		Return emissiontype
	End
	Method EmissionType:Void(value:Int) Property
		emissiontype = value
	End
	Method EllipseArc:Float() Property
		Return ellipsearc
	End
	Method EllipseArc:Void(value:Float) Property
		ellipsearc = value
	End
	Method EllipseOffset:Int() Property
		Return ellipseoffset
	End
	Method EllipseOffset:Void(value:Int) Property
		ellipseoffset = value
	End
	Method EffectLength:Int() Property
		Return effectlength
	End
	Method EffectLength:Void(value:Int) Property
		effectlength = value
	End
	Method Uniform:Int() Property
		Return uniform
	End
	Method Uniform:Void(value:Int) Property
		uniform = value
	End
	Method TraverseEdge:Int() Property
		Return traverseedge
	End
	Method TraverseEdge:Void(value:Int) Property
		traverseedge = value
	End
	Method EndBehaviour:Int() Property
		Return endbehaviour
	End
	Method EndBehaviour:Void(value:Int) Property
		endbehaviour = value
	End
	Method DistanceSetByLife:Int() Property
		Return distancesetbylife
	End
	Method DistanceSetByLife:Void(value:Int) Property
		distancesetbylife = value
	End
	Method ReverseSpawnDirection:Int() Property
		Return reversespawndirection
	End
	Method ReverseSpawnDirection:Void(value:Int) Property
		reversespawndirection = value
	End
	Method SpawnDirection:Int() Property
		Return spawndirection
	End
	Method SpawnDirection:Void(value:Int) Property
		spawndirection = value
	End
	Method AnimWidth:Int() Property
		Return animwidth
	End
	Method AnimWidth:Void(value:Int) Property
		animwidth = value
	End
	Method AnimHeight:Int() Property
		Return animheight
	End
	Method AnimHeight:Void(value:Int) Property
		animheight = value
	End
	Method AnimX:Void(value:Int) Property
		animx = value
	End
	Method AnimX:Int() Property
		Return animx
	End
	Method AnimY:Void(value:Int) Property
		animy = value
	End
	Method AnimY:Int() Property
		Return animy
	End
	Method Seed:Void(value:Int) Property
		seed = value
	End
	Method Seed:Int() Property
		Return seed
	End
	Method Looped:Void(value:Int) Property
		looped = value
	End
	Method Looped:Int() Property
		Return looped
	End
	Method FrameOffset:Void(value:Int) Property
		frameoffset = value
	End
	Method FrameOffset:Int() Property
		Return frameoffset
	End
	Method AnimZoom:Void(value:Float) Property
		animzoom = value
	End
	Method AnimZoom:Float() Property
		Return animzoom
	End
	Method CurrentSizeX:Void(value:Float) Property
		currentsizex = value
	End
	Method CurrentSizeX:Float() Property
		Return currentsizex
	End
	Method CurrentSizeY:Void(value:Float) Property
		currentsizey = value
	End
	Method CurrentSizeY:Float() Property
		Return currentsizey
	End
	Method CurrentVelocity:Void(value:Float) Property
		currentvelocity = value
	End
	Method CurrentVelocity:Float() Property
		Return currentvelocity
	End
	Method CurrentSpin:Void(value:Float) Property
		currentspin = value
	End
	Method CurrentSpin:Float() Property
		Return currentspin
	End
	Method CurrentWeight:Void(value:Float) Property
		currentweight = value
	End
	Method CurrentWeight:Float() Property
		Return currentweight
	End
	Method CurrentAreaWidth:Void(value:Float) Property
		currentareawidth = value
	End
	Method CurrentAreaWidth:Float() Property
		Return currentareawidth
	End
	Method CurrentAreaHeight:Void(value:Float) Property
		currentareaheight = value
	End
	Method CurrentAreaHeight:Float() Property
		Return currentareaheight
	End
	Method CurrentAlpha:Void(value:Float) Property
		currentalpha = value
	End
	Method CurrentAlpha:Float() Property
		Return currentalpha
	End
	Method CurrentEmissionAngle:Void(value:Float) Property
		currentemissionangle = value
	End
	Method CurrentEmissionAngle:Float() Property
		Return currentemissionangle
	End
	Method CurrentEmissionRange:Void(value:Float) Property
		currentemissionrange = value
	End
	Method CurrentEmissionRange:Float() Property
		Return currentemissionrange
	End
	Method CurrentStretch:Void(value:Float) Property
		currentstretch = value
	End
	Method CurrentStretch:Float() Property
		Return currentstretch
	End
	Method CurrentGlobalZoom:Void(value:Float) Property
		currentglobalzoom = value
	End
	Method CurrentGlobalZoom:Float() Property
		Return currentglobalzoom
	End
	Method Data:Void(value:Float) Property
		data = value
	End
	Method Data:Float() Property
		Return data
	End
	
	Method OverrideAreaSize:Void(value:Int) Property
		overrideareasize = value
	End
	Method OverrideAreaSize:Int() Property
		Return overrideareasize
	End
	Method OverrideEmissionAngle:Void(value:Int) Property
		overrideemissionangle = value
	End
	Method OverrideEmissionAngle:Int() Property
		Return overrideemissionangle
	End
	Method OverrideEmissionRange:Void(value:Int) Property
		overrideemissionrange = value
	End
	Method OverrideEmissionRange:Int() Property
		Return overrideemissionrange
	End
	Method OverrideAngle:Void(value:Int) Property
		overrideangle = value
	End
	Method OverrideAngle:Int() Property
		Return overrideangle
	End
	Method OverrideLife:Void(value:Int) Property
		overridelife = value
	End
	Method OverrideLife:Int() Property
		Return overridelife
	End
	Method OverrideAmount:Void(value:Int) Property
		overrideamount = value
	End
	Method OverrideAmount:Int() Property
		Return overrideamount
	End
	Method OverrideVelocity:Void(value:Int) Property
		overridevelocity = value
	End
	Method OverrideVelocity:Int() Property
		Return overridevelocity
	End
	Method OverrideSpin:Void(value:Int) Property
		overridespin = value
	End
	Method OverrideSpin:Int() Property
		Return overridespin
	End
	Method OverrideSizeX:Void(value:Int) Property
		overridesizex = value
	End
	Method OverrideSizeX:Int() Property
		Return overridesizex
	End
	Method OverrideSizeY:Void(value:Int) Property
		overridesizey = value
	End
	Method OverrideSizeY:Int() Property
		Return overridesizey
	End
	Method OverrideWeight:Void(value:Int) Property
		overrideweight = value
	End
	Method OverrideWeight:Int() Property
		Return overrideweight
	End
	Method OverrideAlpha:Void(value:Int) Property
		overridealpha = value
	End
	Method OverrideAlpha:Int() Property
		Return overridealpha
	End
	Method OverrideStretch:Void(value:Int) Property
		overridestretch = value
	End
	Method OverrideStretch:Int() Property
		Return overridestretch
	End
	Method OverrideGlobalZoom:Void(value:Int) Property
		overrideglobalzoom = value
	End
	Method OverrideGlobalZoom:Int() Property
		Return overrideglobalzoom
	End
	
	Method ParticleManager:Void(value:tlParticleManager) Property
		pm = value
	End
	Method ParticleManager:tlParticleManager() Property
		Return pm
	End
	
	'Main Effect Setters
	
	#REM
		summary: Set the area size of the effect
		If the effect is Area or Elipse then you can use this to change the dimensions of it.
	#END
	Method SetAreaSize:Void(Width:Float, Height:Float)
		overrideareasize = True
		currentareawidth = Width
		currentareaheight = Height
	End Method
	
	#Rem
		summary: Set the line length of the effect
		For line effects, use this function to override the graph and set the length of the line to whatever you want.
	#END
	Method SetLineLength:Void(Length:Float)
		overrideareasize = True
		currentareawidth = Length
	End Method
	#Rem
		summary: Set the Emission Angle of the effect
		This overides whatever angle is set on the graph and sets the emission angle of the effect. This won't effect emitters that have <i>UseEffectEmission</i> set
		to FALSE.
	#END
	Method SetEmissionAngle:Void(angle:Float)
		overrideemissionangle = True
		currentemissionangle = angle
	End Method
	#Rem
		summary: Set the Angle of the effect
		This overides the whatever angle is set on the graph and sets the angle of the effect.
	#END
	Method SetEffectAngle:Void(Angle:Float)
		If Angle < 0 Angle += 360
		overrideangle = True
		LocalRotation = Angle
	End Method
	#Rem
		summary: Set the Global attribute Life of the effect
		This overides the graph the effect uses to set the Global Attribute Life
	#END
	Method SetLife:Void(life:Float)
		overridelife = True
		currentlife = life
	End Method
	#Rem
		summary: Set the Global attribute Amount of the effect
		This overides the graph the effect uses to set the Global Attribute Amount
	#END
	Method SetAmount:Void(amount:Float)
		overrideamount = True
		currentamount = amount
	End Method
	#Rem
		summary: Set the Global attribute velocity of the effect
		This overides the graph the effect uses to set the Global Attribute velocity
	#END
	Method SetVelocity:Void(velocity:Float)
		overridevelocity = True
		currentvelocity = velocity
	End Method
	#Rem
		summary: Set the Global attribute Spin of the effect
		This overides the graph the effect uses to set the Global Attribute Spin
	#END
	Method SetSpin:Void(spin:Float)
		overridespin = True
		currentspin = Spin
	End Method
	#Rem
	summary: Set the Global attribute Weight of the effect
	This overides the graph the effect uses to set the Global Attribute Weight
	#END
	Method SetWeight:Void(Weight:Float)
		overrideweight = True
		currentweight = Weight
	End Method
	#Rem
		summary: Set the Global attribute Sizex of the effect
		This overides the graph the effect uses to set the Global Attribute Sizex and sizey
	#END
	Method SetEffectParticleSize:Void(Sizex:Float, Sizey:Float)
		overridesizex = True
		overridesizey = True
		currentsizex = Sizex
		currentsizey = Sizey
	End Method
	#Rem
		summary: Set the Global attribute Sizex and Sizey of the effect
		This overides the graph the effect uses to set the Global Attribute Sizex and Sizey. You can use this method if your effect changes particle sizes uniformly. Although even if it doesn't you can still
		use this effect it will just change both sizex and size to the same values.
	#END
	Method SetSize:Void(Size:Float)
		overridesizex = True
		overridesizey = True
		currentsizex = Size
		currentsizey = Size
	End Method
	#Rem
		summary: Set the Global attribute Sizex of the effect
		This overides the graph the effect uses to set the Global Attribute Sizex
	#END
	Method SetSizeX:Void(Sizex:Float)
		overridesizex = True
		currentsizex = Sizex
	End Method
	#Rem
		summary: Set the Global attribute Sizey of the effect
		This overides the graph the effect uses to set the Global Attribute Sizey. Note that if 
	#END
	Method SetSizeY:Void(Sizey:Float)
		overridesizey = True
		currentsizey = Sizey
	End Method
	#Rem
		summary: Set the Global attribute Alpha of the effect
		This overides the graph the effect uses to set the Global Attribute Alpha
	#END
	Method SetEffectAlpha:Void(Alpha:Float)
		overridealpha = True
		currentalpha = Alpha
	End Method
	#Rem
		summary: Set the Global attribute EmissionRange of the effect
		This overides the graph the effect uses to set the Global Attribute EmissionRange
	#END
	Method SetEffectEmissionRange:Void(EmissionRange:Float)
		overrideemissionrange = True
		currentemissionrange = EmissionRange
	End Method
	#Rem
			Set the current zoom level of the effect
			This overides the graph the effect uses to set the Global Attribute Global Zoom and can be used to scale the size of the whole effect.
	#END
	Method SetZ:Void(v:Float)
		overrideglobalzoom = True
		Zoom = v
	End Method
	#Rem
			Set the current zoom level of the effect
			This overides the graph the effect uses to set the Global Attribute Global Zoom
	#END
	Method SetGlobalZoom:Void(v:Float)
		overrideglobalzoom = True
		Zoom = v
	End Method
	#Rem
		summary: Set the Global attribute Stretch of the effect
		This overides the graph the effect uses to set the Global Attribute Stretch
	#END
	Method SetStretch:Void(v:Float)
		overridestretch = True
		currentstretch = v
	End Method
	
	Method SetSpawnDirection:Void()
		If reversespawndirection
			spawndirection = -1
		Else
			spawndirection = 1
		EndIf
	End Method
	
	Method SoftKill()
		Dying = True
	End Method
	
	Method HardKill()
		Destroy()
		pm.RemoveEffect(Self)
	End Method
	
	'Internal Methods
	
	Method CompileAll:Void()
		For Local graph:tlComponent = EachIn Components
			If tlGraphComponent(graph)
				Select tlGraphComponent(graph).GraphType
					Case tlNORMAL_GRAPH
						tlGraphComponent(graph).Compile()
					Case tlOVERTIME_GRAPH
						tlGraphComponent(graph).Compile_Overtime()
				End Select
			End
		Next
		For Local e:tlGameObject = EachIn GetChildren
			tlEmitter(e).CompileAll()
		Next
	End Method
	
	Method ParentHasGraph:Int(graph:String)
		If parentemitter
			If parentemitter.ParentEffect.GetComponent(graph)
				Return True
			EndIf
			Return parentemitter.ParentEffect.ParentHasGraph(graph)
		Else
			Return False
		EndIf
		
	End Method

End

#REM
	summary: Copy an effect
	You should use this command everytime you want to add an effect to the particle, otherwise you'll simply be referencing the effect directly from the library which simply won't work
	if you add more then one of the same effect.
	
	Pass the effect you wish to copy, the particle manager you want it assigned to and if you wish you can copy the directory which allows you to access individual emitters within the effect, in most
	cases though this will be unnecessary.
#END
Function CopyEffect:tlEffect(e:tlEffect, ParticleManager:tlParticleManager, CopyDirectory:Int = False)
	Local clone:tlEffect = New tlEffect
	clone.EffectClass = e.EffectClass
	clone.EmitatPoints = e.EmitatPoints
	clone.MaxGX = e.MaxGX
	clone.MaxGY = e.MaxGY
	clone.EmissionType = e.EmissionType
	clone.EllipseArc = e.EllipseArc
	clone.EffectLength = e.EffectLength
	clone.Uniform = e.Uniform
	clone.TraverseEdge = e.TraverseEdge
	clone.EndBehaviour = e.EndBehaviour
	clone.DistanceSetByLife = e.DistanceSetByLife
	clone.ReverseSpawnDirection = e.ReverseSpawnDirection
	clone.Name = e.Name
	clone.Path = e.Path
	clone.HandleCenter = e.HandleCenter
	clone.HandleVector = e.HandleVector.Clone()
	clone.DoB = ParticleManager.CurrentTime
	clone.ParticleManager = ParticleManager
	clone.SetSpawnDirection()
	
	'temps
	clone.currentamount = e.currentamount
	clone.currentlife = e.currentlife
	clone.currentsizex = e.currentsizex
	clone.currentsizey = e.currentsizey
	clone.currentvelocity = e.currentvelocity
	clone.LocalRotation = e.LocalRotation
	clone.currentspin = e.currentspin
	clone.currentweight = e.currentweight
	clone.currentareawidth = e.currentareawidth
	clone.currentareaheight = e.currentareaheight
	clone.currentalpha = e.currentalpha
	clone.currentemissionangle = e.currentemissionangle
	clone.currentemissionrange = e.currentemissionrange
	clone.currentstretch = e.currentstretch
	clone.currentglobalzoom = e.currentglobalzoom
	clone.SetGlobalZoom(clone.currentglobalzoom)
	
	For Local component:tlComponent = EachIn e.Components
		If tlGraphComponent(component)
			If component.Name = "Angle"
				clone.AddComponent(tlGraphComponent(component).Clone(clone, Null, True))
			Else
				clone.AddComponent(tlGraphComponent(component).Clone(clone))
			EndIf
		EndIf
	Next
	
	For Local emitter:tlGameObject = EachIn e.GetChildren
		Local emitterclone:tlEmitter = CopyEmitter(tlEmitter(emitter), clone, ParticleManager)
		emitterclone.SetParentEffect(clone)
		tlEmitterCoreComponent(emitterclone.GetComponent("Core")).InitSpawner(emitterclone)
		clone.AddChild(emitterclone)
	Next
	
	If CopyDirectory
		If Not clone.Directory clone.Directory = New StringMap<tlGameObject>
		clone.AddEffect(clone)
	EndIf
	
	Return clone
End Function

